package com.qiaofang.applet.service.member.service.impl;

import com.google.common.collect.Lists;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.service.member.domain.Department;
import com.qiaofang.applet.service.member.domain.Employee;
import com.qiaofang.applet.service.member.domain.EmployeeReport;
import com.qiaofang.applet.service.member.repository.EmployeeReportRepository;
import com.qiaofang.applet.service.member.service.DepartmentService;
import com.qiaofang.applet.service.member.service.EmployeeReportService;
import com.qiaofang.applet.service.member.service.dto.*;
import com.qiaofang.applet.service.member.service.mapstruct.EmployeeReportMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.data.domain.Sort.Direction.DESC;

/**
 * @author daiyuxiang
 */
@Slf4j
@Service
public class EmployeeReportServiceImpl extends MongoBaseService<EmployeeReport, String> implements EmployeeReportService {


    private final EmployeeReportRepository repository;

    @Autowired
    public EmployeeReportServiceImpl(EmployeeReportRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private EmployeeReportMapper employeeReportMapper;


    @Override
    public Page<ShareHouseReportDto> getShareHouseReport(OperateReportDto reportDto, Pageable pageable) {
        //处理筛选条件
        Criteria criteria = timeScreenCriteria(reportDto);
        int count = getEmpCount(criteria);
        List<ShareHouseReportDto> list = new ArrayList<>();
        if (count > 0) {
            Aggregation agg = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.sort(DESC, "reportDate"),//分组前排序
                    Aggregation.group("employeeUniqueUuid").first("employeeUniqueUuid").as("employeeUniqueUuid")
                            .first("employeeName").as("employeeName")
                            .first("cityName").as("cityName")
                            .first("deptName").as("deptName")
                            .sum("shareHouse").as("shareHouse")
                            .sum("shareHouseWx").as("shareHouseWx")
                            .sum("shareHousePic").as("shareHousePic")
                            .sum("shareFirsthand").as("shareFirsthand")
                            .sum("shareFirsthandWx").as("shareFirsthandWx")
                            .sum("shareFirsthandPic").as("shareFirsthandPic")
                            .sum("shareSale").as("shareSale")
                            .sum("shareSaleWx").as("shareSaleWx")
                            .sum("shareSalePic").as("shareSalePic")
                            .sum("shareRent").as("shareRent")
                            .sum("shareRentWx").as("shareRentWx")
                            .sum("shareRentPic").as("shareRentPic"),
                    Aggregation.sort(DESC, "shareHouse", "employeeUniqueUuid"),//分组后排序
                    Aggregation.skip(pageable.getOffset()),
                    Aggregation.limit(pageable.getPageSize())
            );
            AggregationResults result = mongoTemplate.aggregate(agg, "member_employee_report", ShareHouseReportDto.class);
            list = result.getMappedResults();
        }

        return PageableExecutionUtils.getPage(list, pageable, () -> count);
    }

    @Override
    public Page<ShareEmpReportDto> getShareEmpReport(OperateReportDto reportDto, Pageable pageable) {
        //处理筛选条件
        Criteria criteria = timeScreenCriteria(reportDto);
        int count = getEmpCount(criteria);
        List<ShareEmpReportDto> list = new ArrayList<>();
        if (count > 0) {
            Aggregation agg = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.sort(DESC, "reportDate"),//分组前排序
                    Aggregation.group("employeeUniqueUuid").first("employeeUniqueUuid").as("employeeUniqueUuid")
                            .first("employeeName").as("employeeName")
                            .first("cityName").as("cityName")
                            .first("deptName").as("deptName")
                            .sum("shareEmp").as("shareEmp")
                            .sum("shareEmpWx").as("shareEmpWx")
                            .sum("shareEmpPic").as("shareEmpPic"),
                    Aggregation.sort(DESC, "shareEmp", "employeeUniqueUuid"),//分组后排序
                    Aggregation.skip(pageable.getOffset()),
                    Aggregation.limit(pageable.getPageSize())
            );
            AggregationResults result = mongoTemplate.aggregate(agg, "member_employee_report", ShareEmpReportDto.class);
            list = result.getMappedResults();
        }

        return PageableExecutionUtils.getPage(list, pageable, () -> count);
    }

    @Override
    public Page<InteractReportDto> getInteractReport(OperateReportDto reportDto, Pageable pageable) {
        //处理筛选条件
        Criteria criteria = timeScreenCriteria(reportDto);
        int count = getEmpCount(criteria);
        List<InteractReportDto> list = new ArrayList<>();
        if (count > 0) {
            Aggregation agg = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.sort(DESC, "reportDate"),//分组前排序
                    Aggregation.group("employeeUniqueUuid")
                            .first("employeeUniqueUuid").as("employeeUniqueUuid")
                            .first("employeeName").as("employeeName")
                            .first("cityName").as("cityName")
                            .first("deptName").as("deptName")
                            .sum("visitNum").as("visitNum")
                            .sum("focusNum").as("focusNum")
                            .sum("fansNum").as("fansNum")
                            .sum("shareNum").as("shareNum")
                            .sum("chatNum").as("chatNum")
                            .sum("callNum").as("callNum")
                            .sum("interactNum").as("interactNum"),
                    Aggregation.sort(DESC, "interactNum", "employeeUniqueUuid"),//分组后排序
                    Aggregation.skip(pageable.getOffset()),
                    Aggregation.limit(pageable.getPageSize())
            );
            AggregationResults result = mongoTemplate.aggregate(agg, "member_employee_report", InteractReportDto.class);
            list = result.getMappedResults();
        }

        return PageableExecutionUtils.getPage(list, pageable, () -> count);
    }

    private Criteria timeScreenCriteria(OperateReportDto reportDto) {
        Criteria criteria = Criteria.where("corporationCode").is(reportDto.getCorporationCode());
        if (StringUtils.isNotEmpty(reportDto.getCityCode())) {
            criteria.and("cityCode").is(reportDto.getCityCode());
        } else if (!CollectionUtils.isEmpty(reportDto.getCityCodes())){
            criteria.and("cityCode").in(reportDto.getCityCodes());
        }
        if (StringUtils.isNotEmpty(reportDto.getDeptUuid())) {
            criteria.and("deptUuid").is(reportDto.getDeptUuid());
        }
        if (reportDto.getBeginDate() != null && reportDto.getEndDate() != null) {
            criteria.and("reportDate").gte(reportDto.getBeginDate()).lt(reportDto.getEndDate());
        } else if (reportDto.getBeginDate() != null) {
            criteria.and("reportDate").gte(reportDto.getBeginDate());
        } else if (reportDto.getEndDate() != null) {
            criteria.and("reportDate").lt(reportDto.getEndDate());
        }
        return criteria;
    }

    private int getEmpCount(Criteria criteria) {
        Aggregation aggCount = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("employeeUniqueUuid").first("employeeUniqueUuid").as("employeeUniqueUuid")
        );
        AggregationResults countResult = mongoTemplate.aggregate(aggCount, "member_employee_report", ReportBaseDto.class);
        return countResult.getMappedResults().size();
    }

    @Override
    public List<EmployeeDailyDto> listTotalEmployeeDaily(String companyUuid) {

        //首先可以获取所有经纪人的房源分享行为数据
        Query query = new Query();
        log.info("开始统计{}公司经纪人日报:", companyUuid);
        Criteria criteria = Criteria.where("companyUuid").is(companyUuid);
        criteria.and("reportDate").gte(getDayZero(DateUtils.addDays(new Date(), -1)));
        query.addCriteria(criteria);
        long l = System.currentTimeMillis();
        List<EmployeeReport> employeeReports = mongoTemplate.find(query, EmployeeReport.class);
        log.info("查找报表数据耗时：{}ms", System.currentTimeMillis() - l);

        List<EmployeeDailyDto> employeeDailyDtoList = Optional.ofNullable(employeeReports).orElseGet(Lists::newArrayList)
                .stream().map(employeeReportMapper::domainToDto).collect(Collectors.toList());
        log.info("{}公司，经纪人数：{}", companyUuid, employeeReports.size());
        //预约
        Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("employeeUniqueUuid")
                        .first("employeeUniqueUuid").as("employeeUniqueUuid")
                        .sum("reservations").as("reservations"));

        AggregationResults<AppointmentAggregateDto> memberAppointment = mongoTemplate.aggregate(agg, "member_appointment", AppointmentAggregateDto.class);
        List<AppointmentAggregateDto> mappedResults = memberAppointment.getMappedResults();

        List<EmployeeDailyDto> resultList;
        long l1 = System.currentTimeMillis();
        if (!CollectionUtils.isEmpty(mappedResults)){
            resultList = employeeDailyDtoList.stream().map(employeeDailyDto -> {
                for (AppointmentAggregateDto mappedResult : mappedResults) {
                    if (StringUtils.equals(mappedResult.getEmployeeUniqueUuid(), employeeDailyDto.getEmployeeUniqueUuid())) {
                        employeeDailyDto.setReservations(mappedResult.getReservations());
                        continue;
                    }
                    employeeDailyDto.setReservations(0L);
                }
                return employeeDailyDto;
            }).collect(Collectors.toList());
        } else {
            resultList = employeeDailyDtoList.stream().map(employeeDailyDto -> {
                employeeDailyDto.setReservations(0L);
                return employeeDailyDto;
            }).collect(Collectors.toList());
        }
        log.info("组装预约耗时：{}ms", System.currentTimeMillis() - l1);
        return resultList;
    }

    private Date getDayZero(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }
}
